package org.sanguine.tests.tenderpro.sax;

import org.sanguine.tests.tenderpro.sax.actions.Action;
import org.sanguine.tests.tenderpro.sax.actions.ElementCounter;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class SaxCheckXML {
    private static SaxXMLWorker worker;
    private static String actionName;
    private static String actionXmlFile;
    private static boolean xsd = false;

    public static void main(String[] args) {

        parseArgs(args);

        List<String> params = Arrays.asList(args);

        ProxyHandler proxy = new ProxyHandler();

        Action counter = new ElementCounter();
        proxy.addCustomHandler(counter);

        //Add custom additional actions here

        if (actionName != null && actionXmlFile != null) {
            Action action = getActionInstance(actionName, actionXmlFile);
            proxy.addCustomHandler(action);
            if (action == null) System.err.println("Class for action " + actionName + " is not found");
        }

        proxy.setUp(params);

        try {
            worker = new SaxXMLWorker(proxy, xsd);
        } catch (ParserConfigurationException e) {
            System.err.println("XML Parser Configuration error");
            e.printStackTrace();
            System.exit(2);
        } catch (SAXException e) {
            System.err.println("XML Content is not valid");
            e.printStackTrace();
            System.exit(2);
        }

        try {
            worker.parse(convetFileToURL(params.get(0)));
        } catch (IOException e) {
            System.err.println("Can't read XML file: " + args[0]);
//            e.printStackTrace();
            System.exit(2);
        } catch (SAXException e) {
            System.err.println("XML Content is not valid");
            e.printStackTrace();
            System.exit(2);
        }
    }

    private static void parseArgs(String[] args) {
        if (args.length < 2) {
            usage();
            System.exit(1);
        }

        if (args.length > 2) {
            List<String> optionalArgs = Arrays.asList(Arrays.copyOfRange(args, 2, args.length));
            if (optionalArgs.contains("-schema")) xsd = true;
            if (optionalArgs.contains("-action") && optionalArgs.contains("-actionXML")) {
                actionName = optionalArgs.get(optionalArgs.indexOf("-action") + 1);
                if (actionName == null || actionName.isEmpty()) {
                    System.err.println("Action name is not set");
                    usage();
                    System.exit(1);
                }
                actionXmlFile = optionalArgs.get(optionalArgs.indexOf("-actionXML") + 1);
                if (actionXmlFile == null || actionXmlFile.isEmpty()) {
                    System.err.println("Action XML file is not set");
                    usage();
                    System.exit(1);
                }
            }
        }
    }

    private static String convetFileToURL(String fileName) {
        String path = new File(fileName).getAbsolutePath();
        if (File.separatorChar != '/') {
            path = path.replace(File.separatorChar, '/');
        }

        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        return "file:" + path;
    }

    private static Action getActionInstance(String actionName, String actionXmlFile) {
        final String ACTION_XPATH = "/actions/action";
        final String ACTION_NAME_ELEMENT = "name";
        final String CLASS_ELEMENT = "class";

        DOMXMLWorker worker = null;

        try {
            worker = new DOMXMLWorker(actionXmlFile, true, actionName);
        } catch (ParserConfigurationException e) {
            System.err.println("XML Parser Configuration error");
            e.printStackTrace();
            System.exit(2);
        } catch (SAXException e) {
            System.err.println("XML Content is not valid");
            e.printStackTrace();
            System.exit(2);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XMLStreamException e) {
            System.err.printf("File %s isn't valid or not found\n", actionName);
            System.exit(2);
        }

        String className = worker.getChildValueForElement(ACTION_XPATH, ACTION_NAME_ELEMENT, CLASS_ELEMENT);
        if (className != null && !className.isEmpty()) {
            try {
                Object o = Class.forName(className.trim()).newInstance();
                if (o instanceof Action) return (Action)o;
                else {
                    System.err.println("Class " + className + " is not implement Action interface");
                    return null;
                }
            } catch (InstantiationException e) {
                System.err.println("Class " + className + " cannot be instantiate");
                e.printStackTrace();
                return null;
            } catch (IllegalAccessException e) {
                System.err.println("Class " + className + " throws IllegalAccessException");
                e.printStackTrace();
                return null;
            } catch (ClassNotFoundException e) {
                System.err.println("Class " + className + " is not found");
                return null;
            }
        }
        else return null;
    }

    private static void usage() {
        System.out.println("Usage: SaxCheckXML FileXML AnElement [-schema] [-action ActionName -actionXML actionXMLFile]");
        System.out.println("Where:");
        System.out.println("\tFileXML  - target XML file");
        System.out.println("\tAnElement - searching element");
        System.out.println("\t-action ActionName (optional) - do additional ActionName's action");
        System.out.println("\t-actionXML actionXMLFile (optional) - actionXMLFile is FileName for action ActionName setting lookup");
    }
}
